package control;

import java.awt.event.KeyEvent;
import model.interfaces.commandTypes.ArmyArgs;
import model.interfaces.commandTypes.DirectionArgs;
import model.interfaces.commandTypes.MoveArgs;
import model.interfaces.commandTypes.NoArgs;
import model.interfaces.selectable.ControllableModel;
import model.interfaces.selectable.ControllablePlayer;
import model.interfaces.selectable.SelectableCommand;
import model.interfaces.selectable.SelectableRallyPoint;
import view.View;

/**
 * Manages the keys for the UnitOverview. The arrowkeys are used to select
 * different rally points. D disbands the selected RP. N + (1-0) creates a new
 * RP with the specified ID.
 * 
 * @author Ross Nichols
 */

class UnitOverviewKeyAdapter extends GameKeyAdapter
{
    private View view;
    private ControllablePlayer player;
    private SelectableRallyPoint[] armies;
    private SelectableRallyPoint army;
    private boolean expectingRallyID = false;
    
    private static final int DISBAND = KeyEvent.VK_D;
    private static final int NEW_RALLY = KeyEvent.VK_N;
    
    /**
     * Upon construction, files away the Player and View.
     */
    public UnitOverviewKeyAdapter( ControllableModel m, View v ) {
        player = m.getPlayer();
        view = v;
    }
    
    /**
     * Upon activation, the overview is opened. Nothing is highlighted by
     * default.
     */
    protected void doActivation()
    {
        System.out.println( "UO activated" );
        armies = player.getRallyPoints();
        army = null;
        view.openOverview( "Unit Overview", transform( armies ), new String[]
        {
            "D disbands", "N-# makes new"
        } );
        view.closeCommandQueue();
        view.setSelectionIndex( -1 );
    }
    
    /**
     * Upon deactivation, the overview is closed.
     */
    protected void doDeactivation()
    {
        System.out.println( "UO deactivated" );
        view.closeOverview();
    }
    
    /**
     * Transformes a SRP[] into a String[] based on its ID and its name.
     */
    private String[] transform( SelectableRallyPoint[] armies )
    {
        String[] ret = new String[ armies.length ];
        for ( int i = 0; i != ret.length; ++i )
            ret[ i ] = String.format( "%s %d", "Rally Point", armies[ i ].getID() );
        
        return ret;
    }
    
    /**
     * Transforms a SC[] into a String[] based on its name.
     */
    private String[] transform( SelectableCommand[] commands )
    {
        String[] ret = new String[ commands.length ];
        for ( int i = 0; i != ret.length; ++i )
            ret[ i ] = commands[ i ].getName();
        
        return ret;
    }
    
    /**
     * Returns the index of an object in an array of the same type.
     */
    private < T > int indexOf( T[] a, T t )
    {
        for ( int i = 0; i != a.length; ++i )
            if ( a[ i ] == t ) return i;
        return -1;
    }
    
    /**
     * Processes the input.
     * 
     * UP/DOWN traverse the list. D disbands the selected army. N flags the
     * system to expect a number corresponding to the ID of a new RP. 1-0 adds a
     * new RP of that ID, if the system was correctly flagged.
     */
    public void keyPressed( KeyEvent e )
    {
        int code = e.getKeyCode();
        if ( (code == KeyEvent.VK_UP || code == KeyEvent.VK_DOWN) && armies.length > 0 )
        {
            int index;
            if ( army == null )
            {
                index = code == KeyEvent.VK_DOWN ? 0 : armies.length - 1;
            }
            else
            {
                int offset = code == KeyEvent.VK_DOWN ? 1 : -1;
                index = (indexOf( armies, army ) + offset) % armies.length;
                if ( index < 0 ) index += armies.length;
            }
            
            army = armies[ index ];
            view.setSelectionIndex( index );
            view.openCommandQueue( transform( army.getQueue() ) );
        }
        else if ( code == DISBAND && army != null )
        {
            army.disband();
            army = null;
            view.setSelectionIndex( -1 );
            view.closeCommandQueue();
            armies = player.getRallyPoints();
            view.setOverview( transform( armies ) );
        }
        else if ( code >= KeyEvent.VK_0 && code <= KeyEvent.VK_9 )
        {
            if ( expectingRallyID )
            {
                int id = -1;
                if ( code >= KeyEvent.VK_1 && code <= KeyEvent.VK_9 )
                {
                    id = code - KeyEvent.VK_0;
                }
                else if ( code == KeyEvent.VK_0 )
                {
                    id = 10;
                }
                boolean exists = false;
                // if the ID exists currently, just select it instead
                for ( SelectableRallyPoint r : armies )
                    if ( r.getID() == id )
                    {
                        exists = true;
                        army = r;
                        view.setSelectionIndex( indexOf( armies, army ) );
                        view.openCommandQueue( transform( army.getQueue() ) );
                    }
                if ( !exists )
                {
                    player.createRallyPoint( id );
                    armies = player.getRallyPoints();
                    view.setOverview( transform( armies ) );
                    for ( SelectableRallyPoint r : armies )
                        if ( r.getID() == id )
                        {
                            army = r;
                            view.setSelectionIndex( indexOf( armies, army ) );
                            view.openCommandQueue( transform( army.getQueue() ) );
                        }
                }
            }
        }
        
        expectingRallyID = code == NEW_RALLY;
    }
    
    /**
     * On tick, make sure our army still exists and update its command queue.
     */
    public void onTick()
    {
        armies = player.getRallyPoints();
        view.setOverview( transform( armies ) );
        int index = indexOf( armies, army );
        
        if ( index == -1 ) army = null;
        
        if ( army == null )
        {
            view.setSelectionIndex( -1 );
            view.closeCommandQueue();
        }
        else
        {
            view.setSelectionIndex( index );
            view.setCommandQueue( transform( army.getQueue() ) );
        }
    }
    
    public void onGameBegin()
    {
        // not needed
    }
    
    public void onGameLose()
    {
        // not needed
    }
    
    public void onGameWin()
    {
        // not needed
    }
    
    public void visitMoveArgs( MoveArgs args )
    {
        // not needed
    }
    
    public void visitArmyArgs( ArmyArgs args )
    {
        // not needed
    }
    
    public void visitDirectionArgs( DirectionArgs args )
    {
        // not needed
    }
    
    public void visitNoArgs( NoArgs args )
    {
        // not needed
    }
}
